import ArrayStack from "../stack";
import GaRegExp from "./ga-reg-exp";
import CatchBuffer from './utils/catch-buffer';
import RuleIndexStack from "./utils/rule-index-stack";
import StackList, { StackInfo } from "../stack-list";

export type RuleType = "equals" | "judge" | "group" | "switch" | "branchs" | "nested" | "func" | "catch" | "range" | "exclude" | "combo" | "once" | "position" | "flat";

export type ParseType = "branch" | "count" | "group" | "switch" | "catch" | "range" | "escape" | "globel" | "unicode" | "position";

export type CharHandle = (save: Set<BranchStack>, origin: BranchStack, rule: StackInfo<RuleInfo>, str: string, index: number, char: string, length: number) => boolean | "next" | "execute";

export type FuncHandle = (save: Set<BranchStack>, origin: BranchStack, rule: StackInfo<RuleInfo>, str: string, index: number, char: string, length: number) => void;

export type RegExpInput = string | RuleInfo | GaRegExp | CharHandle;

export type RuleInfo = (RuleInfoNumber | RuleInfoNever | RuleInfoFuncHandle | RuleInfoCharHandle | RuleInfoNested) & { saveStr?: string; range?: Range; }

export type RuleStack = StackList<RuleInfo>;

export type RuleOptional = Omit<RuleInfo, "ruleData"> & Partial<Pick<RuleInfo, "ruleData">>;

export type RuleOptionalStack = StackList<RuleOptional>;

export type RuleOptionalStackSelect = RuleOptionalStack["selectCheck"];

export interface RuleInfoNumber {
	ruleType: "equals";
	ruleData: number;
}

export interface RuleInfoNever {
	ruleType: "group" | "switch" | "branchs" | "catch" | "range" | "exclude" | "combo" | "once" | "flat";
	ruleData: never;
}

export interface RuleInfoFuncHandle {
	ruleType: "func";
	ruleData: FuncHandle;
}

export interface RuleInfoCharHandle {
	ruleType: "judge" | "position";
	ruleData: CharHandle;
}

export interface RuleInfoNested {
	ruleType: "nested";
	ruleData: GaRegExp;
}

export interface Range { rangeType: "min" | "max"; min: number; max: number; }

export interface RuleParse {

	parseType: ParseType;

	isNested: boolean;

	preHandle: (parse: ArrayStack<RuleParse>, rule: RuleStack, char?: RegExpInput) => void;

	judge: (parse: ArrayStack<RuleParse>, rule: RuleStack, char: string) => boolean;

	// [canNested=true]
	handle: (parse: ArrayStack<RuleParse>, rule: RuleStack, char: string) => boolean;
}

export interface BranchStack {

	index: number;

	ruleIndexStack: RuleIndexStack;

	catchStack: ArrayStack<true>;

	catchBuffer: CatchBuffer;

	countStack: ArrayStack<number>;

	onceStack: ArrayStack<true>;

	onceSet: Set<number>;
}

export interface PickHandle {

	ruleType: RuleType;

	canCount: boolean;

	isNode: boolean;

	// [canCount=false]
	onlyEnter: (save: Set<BranchStack>, origin: BranchStack, str: string, index: number, char: string, length: number) => void;

	enter: (origin: BranchStack, hasRange: boolean) => void;

	// [canCount=true]
	newExit: (enterBranch: BranchStack) => void;

	// [canCount=true]
	reenter: (enterBranch: BranchStack) => void;

	exit: (origin: BranchStack, hasRange: boolean) => void;

	// [isNode=true]
	noodHnalde: CharHandle;

}

export type PickHandleMap = { [ruleType in RuleType]: PickHandle };

export type MatchFormat = string | MatchFormat[];
